package br.edu.ufcg.nokia.battleship;

import java.io.Serializable;

import br.edu.ufcg.nokia.battleship.excecoes.*;

/**
 * Esta classe simula um tabuleiro de um jogo Batalha Naval. O tabuleiro consiste em uma matriz com 10
 * linhas e 10 colunas. Cada elemento da matriz corresponde a uma casa do tabuleiro. 
 * 
 * Os elementos da matriz sao inteiros, cada tipo de navio ou agua corresponde a um inteiro. Ao tabuleiro podem
 * ser adicionados objetos do tipo Navio, os elementos da matriz podem ser modificados, o tabuleiro pode ser 
 * reiniciado, ou seja, todos os elementos da matriz correspondem a agua. 
 *
 * @author Miguel Queiroga, Jackson Azevedo, Edmilson Almeida, Jose Luis
 * @version 1.0
 */

public class Tabuleiro implements Serializable{

	/*
	 * Matriz que guarda o estado de cada "casa" do tabuleiro. Os valores sao:
	 * Agua: 1;
	 * Agua Morta: -1;
	 * Fragata: 2;
	 * Fragata Destruida: -2;
	 * Destroier: 3;
	 * Destroier Destruido: -3;
	 * Encouracado: 4;
	 * Encouracado Destruido: -4;
	 * Porta-Avioes: 5;
	 * Porta-Avioes Destruido: -5;
	 * Submarino: 6;
	 * Sumarino Destruido: -6.
	 */

	/**
	 * 
	 */
	private static final long serialVersionUID = 3093206754657128707L;

	private int tabuleiro[][] = new int[10][10];

	public static final int AGUA = 1;
	public static final int AGUA_MORTA = -1;
	public static final int LIMITE_TABULEIRO = 10;

	/**
	 *  Construtor para um tabuleiro.
	 */

	public Tabuleiro(){
		reinicia();
	}

	/**
	 * Imprime o tabuleiro em forma de strings, com os valores contidos
	 * em cada casa.
	 * @return uma representacao do tabuleiro.
	 */

	public String toString(){
		String saida = "";
		for(int i = 0; i < 10; i++){
			for(int j = 0; j < 10; j++){
				saida += "  " + this.tabuleiro[i][j];
			}
			saida += "\n";
		}
		return saida;
	}

	/**
	 * Obtem o tabuleiro, como uma representacao de matriz de inteiros.
	 * @return A matriz de inteiros do tabuleiro.
	 */

	public int[][] getTabuleiro(){
		return tabuleiro;
	}

	/**
	 * Modifica todo o estado do tabuleiro (todas as casas) para AGUA.
	 */

	public void reinicia(){
		for(int i = 0; i < 10; i++){
			for(int j = 0; j < 10; j++){
				this.tabuleiro[i][j] = AGUA;
			}
		}
	}

	/**
	 * Obtem o conteudo de uma determinada casa do tabuleiro.
	 * @param x Indica em qual coordenada X pegar o conteudo.
	 * @param y Indica em qual coordenada Y pegar o conteudo.
	 * @return O conteudo das coordenadas especificadas.
	 */

	public int getConteudo(int x, int y){
		return tabuleiro[x - 1][y - 1]; // indices da matriz iniciam em 0
	}

	/**
	 * Modifica o conteudo de uma casa do tabuleiro.
	 * @param x Indica em qual coordenada X modificar o conteudo.
	 * @param y Indica em qual coordenada Y modificar o conteudo.
	 * @param valor o valor a ser preenchido na casa que se quer modificar do tabuleiro.
	 */
	
	public void setConteudo(int x, int y, int valor){
		tabuleiro[x - 1][y - 1] = valor;
	}

	/**
	 * Adiciona um Navio no tabuleiro. Se o navio puder ser adicionado.
	 * @param x Indica em qual coordenada X o navio sera adicionado.
	 * @param y Indica em qual coordenada Y o navio sera adicionado.
	 * @param orientacao Indica qual a orientacao do navio. <tt>true</tt>
	 * para vertical e <tt>false</tt> para horizontal.
	 * @param tipo Indica o ipo do navio a ser inserido.
	 * @return <tt>true</tt> se o navio pode ser adicionado, <tt>false</tt> do contrario.
	 */

	public boolean adicionaNavio(int x, int y, boolean orientacao, int tipo) throws LimiteTabuleiroExcedidoException, NavioSobrepostoException{
		int tamanho = 0;
		if (tipo == Navio.SUBMARINO){            //Testa se o tipo e submarino, se for o tamanho sera 3.
			tamanho = 3;
		}else {
			tamanho = tipo;   					//Senao o tamanho sera do tipo de navio passado.
		}
		
		if (orientacao){							//Testa se o navio esta na vertical ou horizontal.
			if (x + tamanho > LIMITE_TABULEIRO + 1){	// Testa se o navio encontra-se fora do tabulerio
				throw new LimiteTabuleiroExcedidoException("Limite do tabuleiro alcancado na LINHA " + x + " COLUNA " + y); 
			}else{																	
				for (int i = x - 1 ; i < x - 1 + tamanho; i++){     // Testa se o navio encontra-se sobre outro.
					if (this.tabuleiro[i][y - 1] != 1) 
					throw new NavioSobrepostoException("Ja existe um navio nesta casa");
				}
				for (int i = x - 1 ; i < x - 1 + tamanho; i++){    // Inclui o navio no tabuleiro.
					this.tabuleiro[i][y-1] = tipo;
				}
				return true;
			}
		}else{												//Executado se o navio estiver na horizontal.
			if (y + tamanho > LIMITE_TABULEIRO + 1){
				throw new LimiteTabuleiroExcedidoException("Limite do tabuleiro alcancado na LINHA " + x + " COLUNA " + y);
			}else{
				for (int i = y - 1 ; i < y - 1 + tamanho; i++){
					if (this.tabuleiro[x - 1][i] != 1) 
					throw new NavioSobrepostoException("Ja existe um navio nesta casa");
				}
				for (int i = y - 1 ; i < y - 1 + tamanho; i++){
					this.tabuleiro[x - 1][i] = tipo;
				}
				return true;
			}
		}
	}

	/**
	 * Verifica no tabuleiro do adversario de o jogador venceu a partida. Se todos os inteiros da matriz do 
	 * tabuleiro que representam navios forem negativos, indica vitoria.
	 * @return <tt>true</tt> se o jogador venceu a partida e <tt>false</tt> do contrario.
	 */
	public boolean verificaVitoria(){
		boolean vitoria = true;
		
		for(int i = 1; i < 11; i++){
			for(int j = 1; j < 11; j++){
				if(this.getConteudo(i,j) > 1){
					vitoria = false;
				}
			}
		}
		return vitoria;
	}
}